using System.Collections.Generic;

namespace InfiniTec.Data
{
    /// <summary>
    /// Represents a multi-valued property of an Exchange item.
    /// </summary>
    /// <typeparam name="T">The type of the property</typeparam>
    public class MultiValuedProperty<T> : Property, IPropertyInfo
    {
        private readonly PropertyValueCollection<T> _Values;

        /// <summary>
        /// Returns a list containing the elements of the property.
        /// </summary>
        public IList<T> Values
        {
            get { return _Values; }
        }

        public PropertyDefinition<T> Definition
        {
            get
            {
                return (PropertyDefinition<T>)((IPropertyInfo)this).PropertyDefinition;
            }
        }

        /// <summary>
        /// Creates a new instance of this class using the specified namespace and local
        /// name.
        /// </summary>
        /// <param name="definition">The definition of the property.</param>
        /// <param name="values">The initial values of the property</param>
        public MultiValuedProperty(PropertyDefinition<T> definition, IEnumerable<T> values) : base(definition)
        {
            _Values = new PropertyValueCollection<T>(this);

            if (values == null) return;

            _Values.AddRange(values);

            SetChanged();
        }

        /// <summary>
        /// Creates a new instance of this class using the specified namespace and local
        /// name.
        /// </summary>
        /// <param name="definition">The definition of the property</param>
        public MultiValuedProperty(PropertyDefinition<T> definition): base(definition)
        {
            _Values = new PropertyValueCollection<T>(this);

            SetChanged();
        }

        bool IPropertyInfo.PropertyValueIsNull { get { return (Values == null || Values.Count == 0); } }

        object IPropertyInfo.Value { get { return Values; } }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
        public override Property Clone()
        {
            MultiValuedProperty<T> result;

            result = new MultiValuedProperty<T>(Definition);
            result._Values.AddRange(Values);

            if (HasChanged)
            {
                result.SetChanged();
            }
            else
            {
                result.ResetChanged();
            }
            result.Status = Status;
            return result;
        }


        public bool Equals(MultiValuedProperty<T> multiValuedProperty)
        {
            if (multiValuedProperty == null) return false;
            if (!base.Equals(multiValuedProperty)) return false;
            return Equals(_Values, multiValuedProperty._Values);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as MultiValuedProperty<T>);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() + 29*(_Values != null ? _Values.GetHashCode() : 0);
        }
    }

}